package com.hsl.hslcodemother.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hsl.hslcodemother.annotation.AuthCheck;
import com.hsl.hslcodemother.common.BaseResponse;
import com.hsl.hslcodemother.common.DeleteRequest;
import com.hsl.hslcodemother.common.ResultUtils;
import com.hsl.hslcodemother.constant.UserConstant;
import com.hsl.hslcodemother.constant.AppConstant;
import com.hsl.hslcodemother.exception.BusinessException;
import com.hsl.hslcodemother.exception.ErrorCode;
import com.hsl.hslcodemother.exception.ThrowUtils;
import com.hsl.hslcodemother.model.dto.app.*;
import com.hsl.hslcodemother.model.entity.App;
import com.hsl.hslcodemother.model.entity.User;
import com.hsl.hslcodemother.model.vo.AppVO;
import com.hsl.hslcodemother.service.AppService;
import com.hsl.hslcodemother.service.UserService;
import com.mybatisflex.core.paginate.Page;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.Map;


@RestController
@RequestMapping("/app")
public class AppController {

    @Autowired
    private AppService appService;

    @Autowired
    private UserService userService;

    // 【用户】创建应用（须填写 initPrompt）
    @PostMapping("/add")
    public BaseResponse<Long> addApp(@RequestBody AppAddRequest addRequest, HttpServletRequest request) {
        if (addRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (addRequest.getAppName() == null || addRequest.getInitPrompt() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "应用名称与 initPrompt 必填");
        }
        User loginUser = userService.getLoginUser(request);
        App app = new App();
        BeanUtil.copyProperties(addRequest, app);
        app.setUserId(loginUser.getId());
        boolean saved = appService.save(app);
        if (!saved) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return ResultUtils.success(app.getId());
    }

    // 【用户】根据 id 修改自己的应用（仅名称）
    @PostMapping("/my/update")
    public BaseResponse<Boolean> updateMyApp(@RequestBody AppMyUpdateRequest myUpdateRequest, HttpServletRequest request) {
        if (myUpdateRequest == null || myUpdateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        App old = appService.getById(myUpdateRequest.getId());
        if (old == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (!old.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        App update = new App();
        update.setId(old.getId());
        update.setAppName(myUpdateRequest.getAppName());
        boolean result = appService.updateById(update);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return ResultUtils.success(true);
    }

    // 【用户】根据 id 删除自己的应用
    @PostMapping("/my/delete")
    public BaseResponse<Boolean> deleteMyApp(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        App old = appService.getById(deleteRequest.getId());
        if (old == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (!old.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean result = appService.removeById(deleteRequest.getId());
        return ResultUtils.success(result);
    }

    // 【用户】根据 id 查看应用详情（VO）
    @GetMapping("/my/get")
    public BaseResponse<AppVO> getMyAppById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        App app = appService.getById(id);
        if (app == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        return ResultUtils.success(appService.getAppVO(app));
    }

    // 【用户】分页查询自己的应用列表（支持名模糊，每页最多 20）
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<AppVO>> listMyApps(@RequestBody AppQueryRequest queryRequest, HttpServletRequest request) {
        if (queryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long pageNum = queryRequest.getPageNum();
        long pageSize = Math.min(queryRequest.getPageSize(), 20);
        User loginUser = userService.getLoginUser(request);
        queryRequest.setUserId(loginUser.getId());
        Page<App> page = appService.page(Page.of(pageNum, pageSize), appService.getQueryWrapper(queryRequest));
        Page<AppVO> voPage = new Page<>(pageNum, pageSize, page.getTotalRow());
        var voList = appService.getAppVOList(page.getRecords());
        voPage.setRecords(appService.fillUsers(voList));
        return ResultUtils.success(voPage);
    }

    // 【用户】分页查询精选的应用列表（支持名模糊，每页最多 20）
    @PostMapping("/featured/list/page/vo")
    public BaseResponse<Page<AppVO>> listFeaturedApps(@RequestBody AppQueryRequest queryRequest) {
        if (queryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long pageNum = queryRequest.getPageNum();
        long pageSize = Math.min(queryRequest.getPageSize(), 20);
        // 精选：优先级 >= GOOD_APP_PRIORITY，按 priority 倒序
        queryRequest.setSortField("priority");
        queryRequest.setSortOrder("descend");
        // 基于通用包装器追加精选条件
        var wrapper = appService.getQueryWrapper(queryRequest);
        wrapper.ge("priority", AppConstant.GOOD_APP_PRIORITY);
        Page<App> page = appService.page(Page.of(pageNum, pageSize), wrapper);
        Page<AppVO> voPage = new Page<>(pageNum, pageSize, page.getTotalRow());
        var voList = appService.getAppVOList(page.getRecords());
        voPage.setRecords(appService.fillUsers(voList));
        return ResultUtils.success(voPage);
    }

    // 【管理员】根据 id 删除任意应用
    @PostMapping("/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest deleteRequest) {
        if (deleteRequest == null || deleteRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean result = appService.removeById(deleteRequest.getId());
        return ResultUtils.success(result);
    }

    // 【管理员】根据 id 更新任意应用（名称、封面、优先级）
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateApp(@RequestBody AppUpdateRequest updateRequest) {
        if (updateRequest == null || updateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        App update = new App();
        BeanUtil.copyProperties(updateRequest, update);
        boolean result = appService.updateById(update);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return ResultUtils.success(true);
    }

    // 【管理员】分页查询应用列表（除时间外任意字段查询、数量不限）
    @PostMapping("/list/page/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<AppVO>> listApps(@RequestBody AppQueryRequest queryRequest) {
        if (queryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long pageNum = queryRequest.getPageNum();
        long pageSize = queryRequest.getPageSize();
        Page<App> page = appService.page(Page.of(pageNum, pageSize), appService.getQueryWrapper(queryRequest));
        Page<AppVO> voPage = new Page<>(pageNum, pageSize, page.getTotalRow());
        var voList = appService.getAppVOList(page.getRecords());
        voPage.setRecords(appService.fillUsers(voList));
        return ResultUtils.success(voPage);
    }

    // 【管理员】根据 id 查看应用详情
    @GetMapping("/get")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<App> getAppById(long id) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        App app = appService.getById(id);
        if (app == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        return ResultUtils.success(app);
    }

    /**
     * 应用聊天生成代码（流式 SSE）
     *
     * @param appId   应用 ID
     * @param message 用户消息
     * @param request 请求对象
     * @return 生成结果流
     */
    @GetMapping(value = "/chat/gen/code", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam Long appId,
                                                       @RequestParam String message,
                                                       HttpServletRequest request) {
        // 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务生成代码（流式）
        Flux<String> contentFlux = appService.chatToGenCode(appId, message, loginUser);
        return contentFlux
                .map(content -> {
                    // 将内容包装成json对象
                    Map<String, String> wrapper = Map.of("d", content);
                    String jsonStr = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder().data(jsonStr).build();
                })
                .concatWith(Flux.just(ServerSentEvent.<String>builder().data("[DONE]").build()));

    }

    /**
     * 应用部署
     *
     * @param appDeployRequest 部署请求
     * @param request          请求
     * @return 部署 URL
     */
    @PostMapping("/deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployRequest appDeployRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appDeployRequest == null, ErrorCode.PARAMS_ERROR);
        Long appId = appDeployRequest.getAppId();
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务部署应用
        String deployUrl = appService.deployApp(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }
}
